
#include <algorithm>
#include <fstream>
#include <sstream>
#include <string>
#include "deformationShape_VSGPU.h"

namespace MLS {
   
///
/// Returns 1 if an OpenGL error occurred, 0 otherwise.
static int gl_error_check() {
   GLenum glErr;
   int retCode = 0;

   glErr = glGetError();
   while (glErr != GL_NO_ERROR) {
      cerr << "glError : " << gluErrorString(glErr) << "\n";
      retCode = 1;
      glErr = glGetError();
   }
   return retCode;
}

DeformationShape_VSGPU::DeformationShape_VSGPU() {
   Deformation::Deformation();
   
   model = 0;
}

DeformationShape_VSGPU::~DeformationShape_VSGPU() {
   
}
   
void DeformationShape_VSGPU::setting(Shape3D *m, const MLS::Constraints *constraints) {
   
   assert(m != 0);
   model = m;
   
   //~ Deformation::setting(model->i_vpositions, model->nvertices(), &constraints->positions);
   
   //~ // Compute the weights table
   //~ if (WeightsTable != 0) delete []WeightsTable;
   
   //~ uint nminusone = std::count(constraints->ids.begin(), constraints->ids.end(), -1);
   //~ if (nminusone == 0) // If all constraints are associated with joints
      //~ WeightsTable = MLS::compute_WeightsTable(model, constraints);
   //~ else if (nminusone < constraints->ids.size()) // If constraints are represented a trihedron
      //~ WeightsTable = MLS::compute_WeightsTable_Trihedrons(model, constraints);
   //~ else
      //~ WeightsTable = 0;
   
   //~ Deformation::initialize();
   
   // Write the constraints number on the source file
   assert(constraints->size()<1000); /// se for maior ver a definacao do 3define no shader
   ostringstream OcpNumber;
   OcpNumber<<constraints->size();
   
   string sdefNconstraints; 
   sdefNconstraints = "#define n " + OcpNumber.str() + " ";
   sdefNconstraints.resize(14,' ');
   
   string shaderFileName;
   shaderFileName = "../mlsrigiddeformer.vs.h";
   
   ofstream fileout(shaderFileName.c_str(), ios::in | ios::out | ios::binary);
   assert(fileout);
   fileout.seekp(0, ios::beg);
   fileout<<sdefNconstraints;
   fileout.close();
   
   assert (!gl_error_check());  // testing all ok
   kernel.vertex_source(shaderFileName.c_str());
   kernel.install();
   
   glActiveTexture(GL_TEXTURE7);
   glGenTextures(1, &texPpoints);
   glBindTexture(GL_TEXTURE_RECTANGLE_NV, texPpoints);
   glTexParameteri(GL_TEXTURE_RECTANGLE_NV, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
   glTexParameteri(GL_TEXTURE_RECTANGLE_NV, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
   glTexImage2D(GL_TEXTURE_RECTANGLE_NV, 0, GL_FLOAT_RGB32_NV, 1, constraints->size(), 0, 
                GL_RGB, GL_FLOAT, &constraints->positions[0][0]);
   //~ checkGLerrors("os P points");
   assert (!gl_error_check());  // testing all ok
   
   glActiveTexture(GL_TEXTURE8);
   glGenTextures(1, &texQpoints);
   glBindTexture(GL_TEXTURE_RECTANGLE_NV, texQpoints);
   glTexParameteri(GL_TEXTURE_RECTANGLE_NV, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
   glTexParameteri(GL_TEXTURE_RECTANGLE_NV, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
   glTexImage2D(GL_TEXTURE_RECTANGLE_NV, 0, GL_FLOAT_RGB32_NV, 1, constraints->size(), 0, 
                GL_RGB, GL_FLOAT, &constraints->positions[0][0]);
   //~ checkGLerrors("os Q points");
   assert (!gl_error_check());  // testing all ok
   
   kernel.use(true);
   kernel.set_uniform("P", 7);
   kernel.set_uniform("Q", 8);
   kernel.use(false);
   //~ checkGLerrors("saindo dos settings");
   assert (!gl_error_check());  // testing all ok
}

void DeformationShape_VSGPU::execute_deformation(const MLS::Constraints *constraints) {
   
   kernel.use(true);
   
   ///< It transfers the Q positions to the GPU memory
   glActiveTexture(GL_TEXTURE8);
   glBindTexture(GL_TEXTURE_RECTANGLE_NV, texQpoints);
   glTexSubImage2D(GL_TEXTURE_RECTANGLE_NV,0,0,0,1,
                  constraints->size(),GL_RGB,GL_FLOAT,&constraints->positions[0][0]);
   
   //~ kernel.set_uniform("Q", 8);
   kernel.use(false);
}

} // end MLS namespace
